﻿using System;
using RenewalProjects.Libraries.Wcf.EasyProxy.ChannelAllocators;
using RenewalProjects.Libraries.Wcf.EasyProxy.ChannelAllocators.Factories;
using RenewalProjects.Libraries.Wcf.EasyProxy.ChannelAllocators.Settings;
using RenewalProjects.Libraries.Wcf.EasyProxy.ChannelHolders;
using RenewalProjects.Libraries.Wcf.EasyProxy.Pools;
using RenewalProjects.Libraries.Wcf.EasyProxy.Tests.TestBuilders;
using Rhino.Mocks;

namespace RenewalProjects.Libraries.Wcf.EasyProxy.Tests.FixtureHelpers
{
	public class PooledChannelAllocatorFixtureHelper<TContract>
	{
		private readonly MockRepository _mock;
		private readonly PoolChannelAllocatorSettings _poolSettings;
		private readonly ChannelFactoryBuilder<TContract> _channelFactoryBuilder;
		private readonly TContract _channelInstance;
		private readonly IResourceItemProvider<ReadyChannelHolder<TContract>> _readyPool;
		private readonly IResourceItemProvider<StandbyChannelHolder<TContract>> _standbyPool;

		public PooledChannelAllocatorFixtureHelper(MockRepository mock, TContract channelInstance)
		{
			_mock = mock;
			_poolSettings = new PoolChannelAllocatorSettings();
			_channelInstance = channelInstance;
			_channelFactoryBuilder = new ChannelFactoryBuilder<TContract>(_mock);
			_readyPool = _mock.StrictMock<IResourceItemProvider<ReadyChannelHolder<TContract>>>();
			_standbyPool = _mock.StrictMock<IResourceItemProvider<StandbyChannelHolder<TContract>>>();

			PooledChannelResourceProviderFactory<TContract>.ReadyChannelHolderFactory = (s) => _readyPool;
			PooledChannelResourceProviderFactory<TContract>.StandbyChannelHolderFactory = (s) => _standbyPool;

			_readyPool.Stub(x => x.ResourceRefillThreshold).PropertyBehavior();
			_readyPool.Stub(x => x.ResourceItemFactory).PropertyBehavior();
			_readyPool.Stub(x => x.RefreshResources());
			_standbyPool.Stub(x => x.ResourceRefillThreshold).PropertyBehavior();
			_standbyPool.Stub(x => x.ResourceItemFactory).PropertyBehavior();
			_standbyPool.Stub(x => x.RefreshResources());
		}

		public PooledChannelAllocatorFixtureHelper<TContract> MakeReadyChannelsAvailable(bool available)
		{
			if(available)
			{
				_poolSettings.ReadyChannelMax = 1;
			}
			else
			{
				_poolSettings.ReadyChannelMax = 0;
			}

			return this;
		}

		public PooledChannelAllocatorFixtureHelper<TContract> MakeStandbyChannelsAvailable(bool available)
		{
			if(available)
			{
				_poolSettings.StandbyChannelMax = 1;
			}
			else
			{
				_poolSettings.StandbyChannelMax = 0;
			}

			return this;
		}

		public PooledChannelAllocatorFixtureHelper<TContract> MakeReadyResourceAvailable(bool available)
		{
			if(available)
			{
				_readyPool.Stub(x => x.GetAvailableResource())
				    .Return(new ReadyChannelHolder<TContract>(_channelInstance, _poolSettings.MaxChannelOpenTime));
			}
			else
			{
				_readyPool.Stub(x => x.GetAvailableResource()).Return(null);
			}

			return this;
		}

		public PooledChannelAllocatorFixtureHelper<TContract> MakeStandbyResourceAvailable(bool available)
		{
			if(available)
			{
				_standbyPool.Stub(x => x.GetAvailableResource())
				    .Return(new StandbyChannelHolder<TContract>(_channelInstance,
						_poolSettings.MaxChannelOpenTime));
			}
			else
			{
				_standbyPool.Stub(x => x.GetAvailableResource()).Return(null);
			}

			return this;
		}
		
		public PooledChannelAllocatorFixtureHelper<TContract> ExpectChannelCreation(bool state)
		{
		    if(state)
		    {
		        _channelFactoryBuilder.ExpectCreateChannel(_channelInstance);
		    }
		    
		    return this;
		}

		public void RefreshChannelPools()
		{
			new PooledChannelAllocator<TContract>(
			        _channelFactoryBuilder.GetFactory(), _channelFactoryBuilder.GetServiceEndpoint(), _poolSettings)
			    .RefreshChannelPools();
		}

		public ChannelHolderBase<TContract> GetAvailableChannel()
		{
			return new PooledChannelAllocator<TContract>(
			               _channelFactoryBuilder.GetFactory(),
			               _channelFactoryBuilder.GetServiceEndpoint(), _poolSettings)
			           .GetAvailableChannel();
		}
	}
}